//
//  UserAccountViewModel.swift
//  MyWeiBlog
//
//  Created by laichunhui on 15/9/28.
//  Copyright © 2015年 lch. All rights reserved.
//

import Foundation

/// 用户账户的视图模型类
/**
在 Swift 中，一个类可以没有任何父类，OC 是必须继承自 NSObject

- NSObject提供了 KVC 的相关方法，如果是模型，通常需要 KVC，应该继承自 NSObject
- 没有父类，所有的都自己实现，量级更轻

视图模型的作用：
1. 封装业务逻辑处理
2. 封装网络代码
3. 封装数据库代码...
4. 把所有的业务逻辑处理从控制器抽取出来，让控制器瘦身！

单元测试，通常不会针对 UI 进行测试！视图模型中，可以通过单元测试对模型直接进行测试，而不需要运行程序！
*/
class UserAccountViewModel {
    
    /// 单例 - 第一次使用的时候，如果沙盒存在用户账户信息，就加载
    private static let instance = UserAccountViewModel()
    class var shareUserAccountViewModel: UserAccountViewModel {
        return instance
    }
    
    /// 用户账户
    var userAccount: UserAccount?
    
    /// 用户登录标记
    var userLogon: Bool {
        return userAccount != nil
    }
    
    /// 用户头像的 URL 地址
    var avatarUrl: NSURL {
        return NSURL(string: userAccount?.avatar_large ?? "")!
    }
    
    /// 保存用户账户文件路径
    var accountPath: String {
        let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
        
        return (path as NSString).stringByAppendingPathComponent("account.plist")
    }
    
    init() {
        // 加载用户账户信息
        UMSocialDataService.defaultDataService().requestSnsInformation(UMShareToSina) { (response) -> Void in
           // access_token", "expires_in", "expiresDate", "uid", "screen_name", "avatar_large"]
            self.userAccount?.user?.screen_name = response.data["screen_name"] as? String
            self.userAccount?.user?.followers_count = (response.data["followers_count"] as? Int)!
            self.userAccount?.user?.friends_count = (response.data["followers_count"] as? Int)!
            //TODO:
            self.userAccount?.user?.gender = response.data["followers_count"] as? String
            self.userAccount?.user?.avatar_large = response.data["followers_count"] as? String
        }

        userAccount = NSKeyedUnarchiver.unarchiveObjectWithFile(accountPath) as? UserAccount
        
        // 判断用户账户是否过期，如果过期，将 userAccount 设置为 nil
        // 通过比较时间的方式
        // if let 会同时过滤两个条件 userAccount == nil，expiresDate == nil
        if let date = userAccount?.expiresDate {
            // 执行到此，日期一定存在
            // compare 可以比较非常多的 NS 对象
            if date.compare(NSDate()) != NSComparisonResult.OrderedDescending {
                userAccount = nil
            }
        }
    }
    
    // MARK: - 网络访问方法
    /**
    1.  新建方法
    2.  复制代码
    3.  修改参数和返回值
    4.  如果有子函数，移动子函数的位置
    5.  测试
    */
    /// 加载 token
    ///
    /// - parameter code:     请求码
    /// - parameter finished: 完成回调 - 没有错误，表示加载成功
    func loadAccessToken(code: String, finished: (error: NSError?)->()) {
        
        NetworkTools.sharedTools.loadAccessToken(code, finished: { (result, error) -> () in
            
            if error != nil {
                finished(error: error)
                return
            }
            
            // 字典转模型，创建用户账户
            let account = UserAccount(dict: result as! [String: AnyObject])
            // 将 account 对象保存在属性中
            self.userAccount = account
            
            // 加载用户信息
            self.loadUserInfo(account, finished: finished)
        })
    }
    
    /// 加载用户信息
    ///
    /// - parameter account: 用户账户
    private func loadUserInfo(account: UserAccount, finished: (error: NSError?)->()) {
        
        NetworkTools.sharedTools.loadUserInfo(account.uid!) { (result, error) -> () in
            
            if error != nil {
                finished(error: error)
                return
            }
            
            // 从 result 字典中提取部分用户信息 - AnyObject 必须转换类型
            guard let dict = result as? [String: AnyObject] else {
                // 所有的异步回调，如果出现 return，一定要有回调，否则控制器不知道执行完成
                finished(error: NSError(domain: "errorLoading", code: -1001, userInfo: ["message": "数据格式错误"]))
                return
            }
            
            // 设置用户信息
            account.screen_name = dict["screen_name"] as? String
            account.avatar_large = dict["avatar_large"] as? String
            
            // 保存用户信息
            account.saveUserAccount()
            
            // 执行回调，通知控制器用户登录完成
            finished(error: nil)
        }
    }
}